/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
TPM_MakeIdentity 
TPM_ActivateIdentity
TPM1.2 中这两个函数用来辅助生成身份证实证书AIK(attestation identity credential)。
TPM2_MakeCredential 
TPM2_ActivateCredential
TPM2 实现类似功能。
TPM2_MakeCredential 这个功能可以不在TPM中完成。

“Make Credential with an object” 这个 object 可以使 EK， 也可以是 TPM 中加载的其他密钥。
TPM2_MakeCredential 使用 object 加载的密钥，根据 protocol 生成一个证书申请blob。
PCA处理证书申请blob后下发AIk到TPM
TPM2_ActivateCredential 验证PCA下发的证书信息，解析解密出下发证书原信息
可以用来做 AIK 证书申请和激活

*/
/*
24 Credential Protection
24.1 Introduction

The TPM supports a privacy preserving protocol for distributing credentials for keys on a TPM.
The process allows a credential provider to assign a credential to a TPM object, such that the credential provider 
cannot prove that the object is resident on a particular TPM，but the credential is not available unless the object 
is resident on a device that the credential provider believes is an authentic TPM.

TPM 支持隐私保护协议，用于在 TPM 上分发密钥凭证（证书）。
该过程允许凭据提供者将凭据分配给 TPM 对象，这样凭据提供者无法证明该对象驻留在特定的 TPM 上，但除非该对象驻留在某个设备上，否则该凭据不可用
凭据提供者认为是真实的 TPM

The credential provider may require that the credential only be useable if the public area is a valid object
on the same TPM as the “EK.” To ensure this, the credential provider encrypts a challenge and then
"wraps" the challenge encryption key with the public key of the “EK.”
凭据提供者可能要求凭据仅在公共区域是有效对象时才可用在与“EK”相同的 TPM 上。 
为确保这一点，凭证提供者对挑战进行加密，然后使用“EK”的公钥“包装”挑战加密密钥。

The encrypted challenge and the wrapped encryption key are then delivered to the initiator. 
The initiator can decrypt the challenge by loading the “EK” and the object onto the TPM and asking the TPM to return the challenge. 
The TPM will decrypt the challenge using the private “EK” and validate that the credentialed object (public and private) is loaded on the TPM. 
If so, the TPM has validated that the properties of the object match the properties required by the credential provider and the TPM will return the challenge.
然后将加密的质询和包装的加密密钥传递给发起者。 发起者可以通过将“EK”和对象加载到 TPM 并要求 TPM 返回挑战来解密挑战。
TPM 将使用私有“EK”解密质询，并验证已在 TPM 上加载凭证对象（公共和私有）。 如果是，则 TPM 已验证对象的属性与凭据提供程序所需的属性匹配，并且 TPM 将返回质询。

This process preserves privacy by allowing TPM objects to have credentials from the credential provider that are not tied to a specific TPM. 
If the object is a signing key, that key may be used to sign attestations, and the credential can assert that the signing key is on a valid 
TPM without disclosing the exact TPM.
此过程通过允许 TPM 对象拥有来自凭证提供者的凭证而不绑定到特定 TPM 来保护隐私。 如果对象是签名密钥，则该密钥可用于签署证明，并且凭证可以断言签名密钥位于有效的 TPM 上，而无需披露确切的 TPM。

TODO: what?
A second property of this protocol is that it prevents the credential provider from proving anything about
the object for which it provided the credential. The credential provider could have produced the credential
with no information from the TPM as the TPM did not need to provide a proof-of-possession of any private
key in order for the credential provider to create the credential. The credential provider can know that the
credential for the object could not be in use unless the object was on the same TPM as the “EK”, but the
credential provider cannot prove it.
该协议的第二个属性是它可以防止凭证提供者证明有关它为其提供凭证的对象的任何信息。 
凭据提供者可以在没有来自 TPM 的信息的情况下生成凭据，因为 TPM 不需要提供任何私钥的所有权证明来让凭据提供者创建凭据。 
凭据提供者可以知道对象的凭据无法使用，除非该对象与“EK”位于同一 TPM 上，但凭据提供者无法证明这一点。

（通常包含用于解密质询的信息）

The credential blob （which typically contains the information used to decrypt the challenge）  
from the credential provider contains a value that is returned by the TPM if the TPM2_ActivateCredential is successful. 
The value may be anything that the credential provider wants to place in the credential blob but is expected to be simply
a large random number.
来自凭据提供程序的凭据blob（通常包含用于解密质询的信息）包含一个值，如果TPM2_ActivateCredential成功，TPM将返回该值。
该值可以是凭证提供者想要放置在凭证blob中的任何值，但预计只是一个大的随机数。

The credential provider protects the credential value (CV) with an integrity HMAC and encryption 
in much the same way as a credential blob. The difference is, when seed is generated, the label 
is “IDENTITY” instead of “DUPLICATE”.
凭证提供者使用完整性HMAC和加密来保护凭证值（CV），其方式与凭证blob非常相似。
不同的是，当生成种子时，标签是“IDENTITY”而不是“DUPLICATE”。 

24.4 Symmetric Encrypt
A seed is derived from values that are protected by the asymmetric algorithm of the “EK”. The methods of 
generating the seed are determined by the asymmetric algorithm of the “EK” and are described in an annex 
to this TPM 2.0 Part 1. In the process of creating seed, the label is required to be “INTEGRITY”
种子是从受“EK”的非对称算法保护的值中派生出来的。生成种子的方法由“EK”的非对称算法确定，并在TPM 2.0第1部分的附件中进行了描述。
在创建种子的过程中，标签必须是““INTEGRITY”。

Given a value for seed, a key is created by:
    symKey ≔ KDFa (ekNameAlg, seed, “STORAGE”, name, NULL , bits) (44)
where
    ekNameAlg the nameAlg of the key serving as the “EK”
    seed the symmetric seed value produced using methods specific to the type of
    asymmetric algorithms of the “EK”
    “STORAGE” a value used to differentiate the uses of the KDF
    name the Name of the object associated with the credential
    bits the number of bits required for the symmetric key

The symKey is used to encrypt the CV. The IV is set to 0.
    encIdentity ≔ CFBekSymAlg (symKey, 0, CV) (45)
where
    CFBekSymAlg symmetric encryption in CFB mode using the symmetric algorithm of the
    key serving as “EK”
    symKey symmetric key from (44)
    CV the credential value (a TPM2B_DIGEST)

24.5 HMAC
A final HMAC operation is applied to the encIdentity value. This is to ensure that the TPM can properly 
associate the credential with a loaded object and to prevent misuse of or tampering with the CV.
最后一个HMAC操作将应用于encIdentity值。这是为了确保TPM能够将凭证与加载的对象正确关联，并防止滥用或篡改CV 

The HMAC key (HMACkey) for the integrity is computed by:
    HMACkey ≔ KDFa (ekNameAlg, seed, “INTEGRITY”, NULL, NULL, bits) (46)
where
    ekNameAlg the nameAlg of the target “EK”
    seed the symmetric seed value used in (44); produced using methods specific
        to the type of asymmetric algorithms of the “EK” 
        在（44）中使用的对称种子值；使用特定于“EK”不对称算法类型的方法生成 
    “INTEGRITY” a value used to differentiate the uses of the KDF
    bits the number of bits in the digest produced by ekNameAlg

NOTE Even though the same value for label is used for each integrity HMAC, seed is created in a manner that 
is unique to the application. Since seed is unique to the application, the HMAC is unique to the application。
尽管每个完整性HMAC使用相同的标签值，但种子是以应用程序特有的方式创建的。由于种子对于应用程序是唯一的，因此HMAC对于应用程序也是唯一的 

HMACkey is then used in the integrity computation.
    identityHMAC ≔ HMACekNameAlg (HMACkey, encIdentity || Name) (47)
where
    HMACekNameAlg the HMAC function using nameAlg of the “EK”
    HMACkey a value derived from the “EK” symmetric protection value according to
        equation (46).
    encIdentity symmetrically encrypted sensitive area produced in (45)
    Name the Name of the object being protected

The integrity structure is constructed by placing the identityHMAC (size and hash) in the buffer ahead of
the encIdentity
*/

/*
This command allows the TPM to perform the actions required of a Certificate Authority (CA) in creating a TPM2B_ID_OBJECT containing an activation credential.
此命令允许TPM执行证书颁发机构（CA）在创建包含激活凭证的TPM2B_ID_OBJECT时所需的操作。

The loaded public area referenced by handle is required to be the public area of a Storage key, otherwise, the credential cannot be properly sealed.
句柄引用的加载的公共区域必须是存储密钥的公共区域，否则，无法正确密封凭据。

The loaded public area referenced by handle is required to be the public area of a Storage key, otherwise, 
the credential cannot be properly sealed.
此命令不使用任何TPM机密，也不需要授权。这是一个方便的功能，使用TPM来执行可以在外部进行的加密计算。

tpm2_makecredential(1) - The TPM supports a privacy preserving protocol for distributing credentials for keys on a TPM. 
The process guarantees that the credentialed-TPM-object(AIK) is loaded on the same TPM as a well-known public-key-object(EK) 
without knowledge of the specific public properties of the credentialed-TPM-object(AIK). The privacy is guaranteed due to the fact 
that only the name of the credentialed-TPM-object(AIK) is shared and not the credentialed-TPM-object's public key itself.
TPM 支持一个保护隐私的协议，用于在 TPM 上分发密钥的凭据（证书）。
这个过程保证认证的 TPM 对象(AIK)被加载到与已知的公钥对象(EK)相同的 TPM 上，而不知道认证的 TPM 对象(AIK)的特定公共属性。
由于只共享凭证 TPM 对象(AIK)的名称，而不共享凭证 TPM 对象的公钥本身，因此保证了隐私性。

24.2 Protocol
Make-credential is the first step in this process where in after receiving the public-key-object(EK) public key of the TPM 
and the name of the credentialed-TPM-object(AIK), an encrypted-user-chosen-data is generated and the secret-data-encryption-key 
is generated and wrapped using cryptographic processes specific to credential activation that guarantees that the credentialed-TPM-object(AIK) 
is loaded on the TPM with the well-known public-key-object(EK).

生成凭证是该过程中的第一步，其中在接收到TPM的公钥对象（EK）公钥和经认证的TPM对象（AIK）的名称之后，生成加密的用户选择的数据，并且使用专用于证书激活的加密过程来生成和封装秘密数据加密密钥。 


tpm2_makecredential can be used to generate the encrypted-user-chosen-data and the wrapped secret-data-encryption-key without a TPM 
by using the none TCTI option.

tpm2_makecredential可用于通过使用none TCTI选项在没有TPM的情况下生成加密的用户选择的数据和封装的秘密数据加密密钥。 
*/

#include "Tpm.h"
#include "MakeCredential_fp.h"

#if CC_MakeCredential  // Conditional expansion of this file

#include "Object_spt_fp.h"

/*(See part 3 specification)
// Make Credential with an object
*/
//  Return Type: TPM_RC
//      TPM_RC_KEY              'handle' referenced an ECC key that has a unique
//                              field that is not a point on the curve of the key
//      TPM_RC_SIZE             'credential' is larger than the digest size of
//                              Name algorithm of 'handle'
//      TPM_RC_TYPE             'handle' does not reference an asymmetric
//                              decryption key
/*
credential value (CV)
1. Marshal the CV into a TPM2B_DIGEST

*/
TPM_RC
TPM2_MakeCredential(
    MakeCredential_In   *in,            // IN: input parameter list
    MakeCredential_Out  *out            // OUT: output parameter list
    )
{
    TPM_RC               result = TPM_RC_SUCCESS;

    OBJECT              *object;
    TPM2B_DATA           data;

// Input Validation

    // Get object pointer
    object = HandleToObject(in->handle);

    // input key must be an asymmetric, restricted decryption key
    // NOTE: Needs to be restricted to have a symmetric value.
    if(!CryptIsAsymAlgorithm(object->publicArea.type)
       || !IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, decrypt)
       || !IS_ATTRIBUTE(object->publicArea.objectAttributes, 
                        TPMA_OBJECT, restricted))
        return TPM_RCS_TYPE + RC_MakeCredential_handle;

    // The credential information may not be larger than the digest size used for
    // the Name of the key associated with handle.
    if(in->credential.t.size > CryptHashGetDigestSize(object->publicArea.nameAlg))
        return TPM_RCS_SIZE + RC_MakeCredential_credential;

// Command Output

    // Make encrypt key and its associated secret structure.
    // 使用 object 指向的密钥对内部生成的随机数进行加密，输出到 out->secret,随机数输出到 data
    /* Part1, B.10.4 RSA Secret Sharing for Credentials
When a credential is protected (such as TPM2_MakeCredential() and TPM2_ActivateCredential()), a
random seed value is created and used as described in B.10.3. The only difference is that the label value
used for the KDF will be “IDENTITY” instead of “DUPLICATE
    */
    out->secret.t.size = sizeof(out->secret.t.secret);
    result = CryptSecretEncrypt(object, IDENTITY_STRING, &data, &out->secret);
    if(result != TPM_RC_SUCCESS)
        return result;

    // Prepare output credential data from secret
    SecretToCredential(&in->credential, &in->objectName.b, &data.b,
                       object, &out->credentialBlob);

    return TPM_RC_SUCCESS;
}

#endif // CC_MakeCredential